<template>
  <n-cascader
    v-bind="props"
    :options="options"
    :check-strategy="checkStrategy"
    :default-value="defaultValueReal"
    @load="handleLoad"
    @update:value="handleUpdate"
  />
</template>

<script setup lang="ts">
  import { onMounted, ref, computed } from 'vue'
  import { NCascader } from 'naive-ui'
  import { useStore } from '@/store'
  import { isArray } from '@/utils/is'
  const store = useStore()

  const emit = defineEmits(['update'])

  const props = defineProps({
    ...NCascader.props,
    checkStrategy: {
      type: String,
      default: 'child'
    },
    placeholder: {
      type: String,
      default: '请选择商品类目'
    },
    separator: {
      type: String,
      default: ' ＞ '
    },
    remote: {
      type: Boolean,
      default: true
    },
    clearable: {
      type: Boolean,
      default: true
    },
    multiple: {
      type: Boolean,
      default: false
    },
    // 数据加载到第几级
    levelLimit: {
      type: Number,
      default: null
    },
    // store.dispatch
    action: {
      type: String,
      default: 'product/getProductCategory'
    },
    defaultValue: {
      type: Array,
      default: () => []
    }
  })

  const options = ref([])
  let loadedDataList: any[] = []
  const defaultValueReal = computed(() => {
    if (isArray(props.defaultValue)) {
      return props.defaultValue[props.defaultValue.length - 1] || null
    }
    return null
  })

  onMounted(async () => {
    options.value = await getProductCategory()
    if (isArray(props.defaultValue)) {
      await dataBackfill()
      if (defaultValueReal.value) {
        const valueList = generateValueList(defaultValueReal.value)
        if (valueList.length !== 0) {
          emit('update', valueList)
        }
      }
    }
  })

  // 数据回填
  async function dataBackfill(parentData = options.value, index = 0) {
    const data = parentData.find((item) => item.value === props.defaultValue[index])
    if (data) {
      data.children = await getProductCategory({ value: props.defaultValue[index] })

      if (index === props.defaultValue.length - 2) return
      await dataBackfill(data.children, ++index)
    }
  }

  async function getProductCategory(option = { value: null }) {
    const { data } = await store.dispatch(props.action, {
      parentId: option.value || null
    })

    const list = data || []
    loadedDataList = [...loadedDataList, ...list]
    return list.map((item) => ({
      label: item.categoryName,
      value: item.id,
      depth: item.categoryLevel,
      isLeaf: (props.levelLimit && item.categoryLevel >= props.levelLimit) || !item.hasChild
    }))
  }

  const handleLoad = (option) => {
    return new Promise<void>(async (resolve) => {
      option.children = await getProductCategory(option)
      resolve()
    })
  }

  function generateValueList(id: IValue) {
    if (isArray(id)) {
      return id.map((item) => formatList(item))
    } else {
      return formatList(id)
    }

    function formatList(id: IValue, valueList: IValueList[] = []) {
      const leafNode = loadedDataList.find((item) => item.id === id)
      if (leafNode) {
        valueList.unshift(leafNode)

        if (leafNode.categoryLevel > 1) {
          formatList(leafNode.parentId, valueList)
        }
      }

      return valueList
    }
  }

  interface IValueList {
    id: number
    categoryName: string
  }

  type IValue = number | string | Array<number | string>
  const handleUpdate = (value: IValue) => {
    const valueList = generateValueList(value)
    emit('update', valueList)
  }
</script>

<style scoped lang="scss"></style>
